import { Canvas, Point } from 'fabric/fabric-impl'
import DaoDaoMindMap from './DaodaoMindMap'
import { fabric } from 'fabric'
import { ChildItem } from './ChildItem'
import { BoundingBox } from './types/global'

export class DragSort {
	topLevel: DaoDaoMindMap
	canvas: Canvas | null
	line: fabric.Path | null
	rect: fabric.Rect
	destinationObject: ChildItem | null
	destinationIndex: number
	constructor(topLevel: DaoDaoMindMap ) {
		this.topLevel = topLevel
		this.canvas = topLevel.canvas
		this.line = null
		this.destinationObject = null
		this.destinationIndex = 0
		this.rect = new fabric.Rect({
			selectable: false,
			fill : 'red', //填充的颜色
			rx: 4, //圆角半径
			ry: 4, //圆角半径
			strokeWidth: 2,
			objectCaching: false,
			left: 0,
			top: 0,
			width: 20,
			height: 10,
			visible:false
		})
		this.init() 
	}
	init() {
		this.canvas?.add(this.rect)
	}
	update(e: fabric.IEvent<MouseEvent>) {
		let rootItem:ChildItem | null = null
		this.destinationIndex = 0
		this.destinationObject = null
		//1. 先计算鼠标拖动到了哪个根元素包围框中，如果一个都没有那就是自由节点
		for(let i=0;i<this.topLevel.mapData.length;i++) {
			const item = this.topLevel.mapData[i]
			if(!item.parent) {
				// 让activeItem元素自身只判断父元素本身包围框
				if(item === this.topLevel.select?.activeItem) {
					if(item.rect.containsPoint(e.absolutePointer as Point, null, true)) {
						rootItem = item
						break
					}
				}else{
					if(item.bounding.containsPoint(e.absolutePointer as Point, null, true)) {
						rootItem = item
						break
					}
				}
			}
		}
		if(!rootItem) {
			this.destinationIndex = 0
			this.destinationObject = null
		}else{
			let isInThisLevel = true
			//2. 进一步计算鼠标拖动到了该根元素的哪个子元素框中
			while(isInThisLevel) {
				isInThisLevel = false
				for(let i=0;i<rootItem.children.length;i++) {
					if(rootItem.children[i].visible && rootItem.children[i].bounding.containsPoint(e.absolutePointer as Point, null, true)) {
						isInThisLevel = true
						rootItem = rootItem?.children[i]
						break
					}
				}
			}
			//3. 进一步判断应该把元素拖动到哪里，并把结果存下来
			if(rootItem.children.length > 0 && rootItem.tempChildrenVisible) {
				// 如果有子元素，根据坐标判断应该拖拽的index
				const pointY = (e.absolutePointer as Point).y
				this.destinationObject = rootItem
				if(pointY < this.getBoundingMiddleY(rootItem.children[0].boundingBoxWidthChild)) {
					this.destinationIndex = 0
				}
				for(let i = 0;i<rootItem.children.length-1;i++) {
					const middleY = this.getBoundingMiddleY(rootItem.children[i].boundingBoxWidthChild)
					const middleY1 = this.getBoundingMiddleY(rootItem.children[i + 1].boundingBoxWidthChild)
					if(pointY > middleY && pointY < middleY1) {
						this.destinationIndex = i + 1
						break
					}
				}
				if(pointY > this.getBoundingMiddleY(rootItem.children[rootItem.children.length - 1].boundingBoxWidthChild)) {
					this.destinationIndex = rootItem.children.length
				}
			}else{
				// 判断rootItem有没有子元素，如果没有就插入为第一个子元素
				this.destinationObject = rootItem
				this.destinationIndex = 0
			}
		}
		//4. 更新显示
		if(this.destinationObject) {
			if(this.destinationObject === this.topLevel.select?.activeItem){
				this.rect.setOptions({
					visible: false
				})
				if(this.line)this.canvas&&this.canvas.remove(this.line)
			}else{
				let top = 0
				const left = this.destinationObject.boundingBoxWidthChild.left+ this.destinationObject.getWidth() + this.topLevel.afterLineLength + this.topLevel.frontLineLength + 5
				if(this.destinationIndex < this.destinationObject.children.length) {
					top = this.destinationObject.children[this.destinationIndex].boundingBoxWidthChild.top - 10
				}else{
					if(this.destinationObject.children.length === 0) {
						top = this.getBoundingMiddleY(this.destinationObject.boundingBoxWidthChild) - 5
					}else{
						top = this.destinationObject.children[this.destinationIndex - 1].boundingBoxWidthChild.bottom
					}
				}
				this.rect.setOptions({
					top: top,
					left: left,
					visible: true
				})
				const x0 = this.destinationObject.boundingBoxWidthChild.left+ this.destinationObject.getWidth()
				const x1 = left
				const y0 = this.getBoundingMiddleY(this.destinationObject.boundingBoxWidthChild)
				const y1 = top + 5

				if(!this.line) {
					this.line = new fabric.Path(`M ${x0} ${y0} L ${x0 + this.topLevel.afterLineLength} ${y0} Q ${x0 + this.topLevel.afterLineLength}, ${y1}, ${x1}, ${y1}`, { fill: '', stroke: 'red', objectCaching: false, selectable: false })
					this.canvas&&this.canvas.add(this.line)
				}else{
					this.canvas&&this.canvas.remove(this.line)
					this.line = new fabric.Path(`M ${x0} ${y0} L ${x0 + this.topLevel.afterLineLength} ${y0} Q ${x0 + this.topLevel.afterLineLength}, ${y1}, ${x1}, ${y1}`, { fill: '', stroke: 'red', objectCaching: false, selectable: false })
					this.canvas&&this.canvas.add(this.line)
				}
			}
			this.canvas?.requestRenderAll()
		}else{
			this.rect.setOptions({
				top: (e.absolutePointer as Point).y,
				left: (e.absolutePointer as Point).x,
				visible: true
			})
			if(this.line) this.canvas&&this.canvas.remove(this.line)
			this.canvas?.requestRenderAll()
		}
	}
	save() {
		if(this.topLevel.select?.activeItem !== this.destinationObject) {
			if(this.topLevel.select?.activeItem){
				// 删除原本的
				if(this.topLevel.select.activeItem.parent){
					const index = this.topLevel.select.activeItem.parent.children.findIndex((item:ChildItem) => item === this.topLevel.select?.activeItem)
					if(index > -1) {
						this.topLevel.select.activeItem.parent.children.splice(index, 1)
					}
					// 判断即将插入的元素是不是当前元素的父元素，如果是就需要判断该元素的原始index
					if(this.topLevel.select.activeItem.parent === this.destinationObject) {
						if(index < this.destinationIndex) {
							this.destinationIndex -= 1
						}
					}
				}
				
				// 重置父元素
				this.topLevel.select.activeItem.parent = this.destinationObject
				// 插入子元素
				if(this.destinationObject ) {
					this.destinationObject.children.splice(this.destinationIndex,0, this.topLevel.select.activeItem)
				}else{
					this.topLevel.select.activeItem.changePosition({x:this.rect.left || 0, y:this.rect.top || 0})
				}
				this.topLevel.countMapPosition()
				this.topLevel._refresh()
			}
		}
		this.reset()
	}
	reset() {
		this.rect.setOptions({
			visible: false
		})
		if(this.line)this.canvas&&this.canvas.remove(this.line)
		this.destinationObject = null
		this.destinationIndex = 0
		this.canvas?.requestRenderAll()
	}
	getBoundingMiddleY(box: BoundingBox) {
		return (box.top + box.bottom)/2
	}
}